package com.itheima.server.service;

import com.itheima.commons.template.OssTemplate;
import com.itheima.domain.db.User;
import com.itheima.domain.db.UserFreeze;
import com.itheima.domain.db.UserInfo;
import com.itheima.domain.mongo.Comment;
import com.itheima.domain.mongo.Publish;
import com.itheima.domain.mongo.Visitor;
import com.itheima.domain.vo.ErrorResult;
import com.itheima.domain.vo.PageResult;
import com.itheima.domain.vo.PublishVo;
import com.itheima.domain.vo.VisitorVo;
import com.itheima.dubbo.api.*;
import com.itheima.server.client.UserFreezeClient;
import com.itheima.server.interceptor.UserHolder;
import com.itheima.server.util.RelativeDateFormat;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author 阿鹏
 * @date 2021/1/28 14:59
 */
@Service
public class MovementService {

    @Reference
    private PublishApi publishApi;
    @Reference
    private UserInfoApi userInfoApi;
    @Reference
    private CommentApi commentApi;
    @Reference
    private VisitorApi visitorApi;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private MovementMQService movementMQService;
    @Autowired
    @Lazy
    private UserFreezeClient client;

    public ResponseEntity saveMovement(Publish publish, MultipartFile[] imageContent) throws IOException {
        Long userId = UserHolder.getUserId();
        String str = redisTemplate.opsForValue().get("USER_PREFIX_" + userId);
        if (StringUtils.isNotBlank(str)) {
            UserFreeze freeze = client.findByUserId(userId);
            if (freeze.getFreezingRange() == 3) {
                // 如果是冻结发布动态
                return ResponseEntity.status(500).body(ErrorResult.publishInvalid());
            }
        }

        List<String> medias = new ArrayList<>();
        for (MultipartFile image : imageContent) {
            String path = ossTemplate.upload(image.getOriginalFilename(), image.getInputStream());
            medias.add(path);
        }
        // 设置多张图片的路径
        publish.setMedias(medias);

        publish.setUserId(UserHolder.getUserId());

        // 待审核
        publish.setState(0);

        // 保存动态
        String publishId = publishApi.save(publish);

        // 发送消息
        rocketMQTemplate.convertAndSend("tanhua-publish9", publishId);

        movementMQService.savePublish(publishId);

        return ResponseEntity.ok(null);
    }

    /**
     * 查询好友动态
     * @param page
     * @param pagesize
     * @return
     */
    public ResponseEntity getMovement(int page, int pagesize) {
        Long userId = UserHolder.getUserId();
        PageResult<Publish> pageResult = publishApi.findByTimeline(page, pagesize, userId);

        List<PublishVo> voList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(pageResult.getItems())) {
            for (Publish publish : pageResult.getItems()) {
                if (publish.getState() == 1) {
                    PublishVo publishVo = new PublishVo();
                    UserInfo userInfo = userInfoApi.findById(publish.getUserId());
                    // 封装userinfo信息
                    BeanUtils.copyProperties(userInfo, publishVo);
                    if (userInfo.getTags() != null) {
                        publishVo.setTags(userInfo.getTags().split(","));
                    }

                    // 封装publish信息
                    BeanUtils.copyProperties(publish, publishVo);
                    publishVo.setId(publish.getId().toHexString());
                    publishVo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));

                    // 当前用户是否点赞了这条动态
                    Boolean hasLiked = redisTemplate.hasKey("publish_comment_like_" + userId + "_" + publish.getId().toHexString());
                    publishVo.setHasLiked(hasLiked ? 1 : 0);

                    Boolean hasLoved = redisTemplate.hasKey("publish_comment_love_" + userId + "_" + publish.getId().toHexString());
                    publishVo.setHasLoved(hasLoved ? 1 : 0);

                    publishVo.setImageContent(publish.getMedias().toArray(new String[]{}));
                    publishVo.setDistance("50米");

                    voList.add(publishVo);
                }
            }
        }

        PageResult<PublishVo> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(pageResult, voPageResult);
        voPageResult.setItems(voList);
        return ResponseEntity.ok(voPageResult);
    }

    public ResponseEntity findRecommend(int page, int pagesize) {
        Long userId = UserHolder.getUserId();
        PageResult<Publish> pageResult = findPublishRecommentByRedis(page, pagesize);
        if (pageResult == null) {
            pageResult = publishApi.findByRecommend(page, pagesize, userId);
        }

        List<PublishVo> voList = new ArrayList<>();

        for (Publish publish : pageResult.getItems()) {
            PublishVo vo = new PublishVo();
            vo.setId(publish.getId().toHexString());
            UserInfo userInfo = userInfoApi.findById(publish.getUserId());
            BeanUtils.copyProperties(userInfo, vo);
            if (userInfo.getTags() != null) {
                vo.setTags(userInfo.getTags().split(","));
            }

            BeanUtils.copyProperties(publish, vo);
            vo.setId(publish.getId().toHexString());
            vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));
            Boolean hasLiked = redisTemplate.hasKey("publish_comment_like_" + userId + "_" + publish.getId().toHexString());
            vo.setHasLiked(hasLiked ? 1 : 0);
            Boolean hasLoved = redisTemplate.hasKey("publish_comment_love_" + userId + "_" + publish.getId().toHexString());
            vo.setHasLoved(hasLoved ? 1 : 0);
            vo.setImageContent(publish.getMedias().toArray(new String[]{}));
            vo.setDistance("50米");
            voList.add(vo);
        }

        PageResult<PublishVo> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(pageResult, voPageResult);
        voPageResult.setItems(voList);
        return ResponseEntity.ok(voPageResult);
    }

    private PageResult<Publish> findPublishRecommentByRedis(int page, int pagesize) {
        String pidStr = redisTemplate.opsForValue().get("QUANZI_PUBLISH_RECOMMEND_" + UserHolder.getUserId());
        if (pidStr == null) {
            return null;
        }

        String[] pidArray = pidStr.split(",");
        int count = pidArray.length;
        int pages = (int) Math.ceil(count * 1.0 / pagesize);

        if (page <= pages) {
            int start = (page - 1) * pagesize;
            int end = start + pagesize;
            if (end > count) {
                end = count;
            }

            List<Long> pidList = new ArrayList<>();
            for (int i = start; i < end; i++) {
                Long pid = Long.valueOf(pidArray[i]);
                pidList.add(pid);
            }

            List<Publish> publishList = publishApi.findByPidList(pidList);

            return new PageResult<>(count, pagesize, pages, page, publishList);
        }
        return new PageResult<>();
    }

    public ResponseEntity getAlbumList(int page, int pagesize, Long userId) {
        if (userId == null) {
            userId = UserHolder.getUserId();
        }

        PageResult<Publish> albumList = publishApi.findAlbumList(page, pagesize, userId);

        List<PublishVo> voList = new ArrayList<>();
        for (Publish publish : albumList.getItems()) {
            // 如果是已审核 就进行封装显示
            if (publish.getState() == 1) {
                PublishVo vo = new PublishVo();

                UserInfo userInfo = userInfoApi.findById(publish.getUserId());
                BeanUtils.copyProperties(userInfo, vo);
                if (userInfo.getTags() != null) {
                    vo.setTags(userInfo.getTags().split(","));
                }
                // 封装动态信息
                BeanUtils.copyProperties(publish, vo);
                vo.setId(publish.getId().toHexString());
                vo.setImageContent(publish.getMedias().toArray(new String[]{}));
                vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));
                vo.setDistance("50米");

                Boolean hasLike = redisTemplate.hasKey("publish_comment_like_" + userId + "_" + publish.getId().toHexString());
                vo.setHasLiked(hasLike ? 1 : 0);
                Boolean hasLove = redisTemplate.hasKey("publish_comment_love_" + userId + "_" + publish.getId().toHexString());
                vo.setHasLoved(hasLove ? 1 : 0);

                voList.add(vo);
            }

        }

        // 封装返回值
        PageResult<PublishVo> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(albumList, voPageResult);
        voPageResult.setItems(voList);
        return ResponseEntity.ok(voPageResult);
    }

    public ResponseEntity saveLike(String publishId) {
        Long userId = UserHolder.getUserId();
        // 封装Comment对象
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setUserId(userId);
        comment.setPubType(1);
        comment.setCommentType(1);

        Publish publish = publishApi.findById(publishId);
        comment.setPublishUserId(publish.getUserId());

        // 调用api 保存对象
        long count = commentApi.save(comment);

        // 将结果保存到redis中
        redisTemplate.opsForValue().set("publish_comment_like_" + userId + "_" + publishId, "1");

        movementMQService.likePublish(publishId);

        return ResponseEntity.ok(count);
    }

    public ResponseEntity removeLike(String publishId) {
        Long userId = UserHolder.getUserId();

        // 封装comment对象
        Comment comment = new Comment();
        comment.setUserId(userId);
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(1);

        // 调用api 删除comment信息对象
        long count = commentApi.remove(comment);

        // 从redis中删除
        redisTemplate.delete("publish_comment_like_" + userId + "_" + publishId);

        movementMQService.dislikePublish(publishId);

        return ResponseEntity.ok(count);
    }

    public ResponseEntity saveLove(String publishId) {
        Long userId = UserHolder.getUserId();

        // 封装comment对象数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setUserId(userId);
        comment.setPubType(1);
        comment.setCommentType(3);

        Publish publish = publishApi.findById(publishId);
        comment.setPublishUserId(publish.getUserId());

        // 调用api，保存comment对象
        long count = commentApi.save(comment);

        redisTemplate.opsForValue().set("publish_comment_love_" + userId + "_" + publishId, "1");

        movementMQService.lovePublish(publishId);

        return ResponseEntity.ok(count);
    }

    public ResponseEntity removeLove(String publishId) {
        Long userId = UserHolder.getUserId();

        // 封装要删除的comment数据
        Comment comment = new Comment();
        comment.setUserId(userId);
        comment.setCommentType(3);
        comment.setPublishId(new ObjectId(publishId));

        // 调用api删除
        long count = commentApi.remove(comment);

        // 删除redis中的数据
        redisTemplate.delete("publish_comment_love_" + userId + "_" + publishId);

        movementMQService.dislovePublish(publishId);

        return ResponseEntity.ok(count);
    }

    public ResponseEntity findPublishDetail(String publishId) {
        Publish publish = publishApi.findById(publishId);
        UserInfo userInfo = userInfoApi.findById(publish.getUserId());
        PublishVo vo = new PublishVo();

        // 封装用户信息
        BeanUtils.copyProperties(userInfo, vo);
        if (userInfo.getTags() != null) {
            vo.setTags(userInfo.getTags().split(","));
        }

        // 封装动态信息
        BeanUtils.copyProperties(publish, vo);

        vo.setId(publish.getId().toHexString());

        vo.setImageContent(publish.getMedias().toArray(new String[]{}));
        vo.setDistance("50米");
        vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));

        Boolean hasLike = redisTemplate.hasKey("publish_comment_like_" + publish.getUserId() + "_" + publishId);
        Boolean hasLove = redisTemplate.hasKey("publish_comment_love_" + publish.getUserId() + "_" + publishId);

        vo.setHasLiked(hasLike ? 1 : 0);
        vo.setHasLoved(hasLove ? 1 : 0);

        movementMQService.watchPublish(publishId);

        return ResponseEntity.ok(vo);
    }

    public ResponseEntity findVisitors() {
        User user = UserHolder.getUser();

        // 先从redis中查询
        String time = redisTemplate.opsForValue().get("visitor_time_" + user.getId());
        List<Visitor> visitors = null;
        if (time == null) {
            // 如果当前访问时间为空,从数据库中查询5条出来
            visitors = visitorApi.findVisitorListByCount(user.getId(), 5);
        } else {
            // 不为空,查询比上次时间更近的访客记录
            visitors = visitorApi.findVisitorListByStartDate(user.getId(), Long.valueOf(time));
        }

        // 把本次访问时间放到redis中存储
        redisTemplate.opsForValue().set("visitor_time_" + user.getId(), String.valueOf(System.currentTimeMillis()));

        // 转换成Vo返回
        List<VisitorVo> voList = new ArrayList<>();
        for (Visitor visitor : visitors) {
            VisitorVo vo = new VisitorVo();

            UserInfo userInfo = userInfoApi.findById(visitor.getVisitorUserId());
            BeanUtils.copyProperties(userInfo, vo);
            vo.setTags(userInfo.getTags().split(","));
            voList.add(vo);
        }
        return ResponseEntity.ok(voList);
    }
}
